package com.jackeys.piaems.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.jackeys.piaems.vo.ResponseVo;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @ClassName: JwtUtil
 * @Description: jwt工具类
 * @Author: Jackeys
 * @Date: 2021-06-19 14:34
 * @Version: 1.0
 */
@Slf4j
public class JwtUtil {

    /**
     * 密钥
     */
    private static String SECRET = "jackeys_secret";

    /**
     * 过期时间（单位：秒）
     **/
    private static long EXPIRATION = 3600;

    /**
     * 黑名单
     */
    private static List<String> backTokenList = new ArrayList<>();

    /**
     * token缓存
     */
    private static Map<String, String> tokenCache = new HashMap<>();

    /**
     * @Name: createToken
     * @Description: 生成用户的token，配置token相关信息，实现生成token的功能
     * @Param: [userId, account, password]
     * @return: java.lang.String
     * @Author: Jackeys
     * @Date: 2021/6/19 14:37
     * @Version: 1.0
     */
    public static String createToken(String account, String password) {
        Map<String, Object> map = new HashMap<>();
        log.debug("生成token中.....");
        map.put("alg", "HS256");
        map.put("typ", "JWT");
        //用户已经登陆过
        String token = JWT.create()
                // 添加头部
                .withHeader(map)
                // 放入用户的id
                .withAudience(account)
                // 可以将基本信息放到claims中
                .withClaim("account", account)
                .withClaim("password", password)
                // 超时设置,设置过期的日期
                .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION * 1000))
                // 签发时间
                .withIssuedAt(new Date())
                // SECRET加密
                .sign(Algorithm.HMAC256(SECRET));
        log.debug("将token存入缓存中......");
        tokenCache.put(account, token);
        return token;
    }

    /**
     * @Name: getUserId
     * @Description: 获取用户id
     * @Param: []
     * @return: java.lang.Integer
     * @Author: Jackeys
     * @Date: 2021/6/19 14:45
     * @Version: 1.0
     */
    public static String getUserAccount(String token) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            if (null != jwt) {
                // 拿到我们放置在token中的信息
                List<String> audience = jwt.getAudience();
                if (null != audience) {
                    return audience.get(0);
                }
            }
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (JWTVerificationException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @Name: verity
     * @Description: 校验token并且解析token
     * @Param: []
     * @return: ResponseResult
     * @Author: Jackeys
     * @Date: 2021/6/19 14:48
     * @Version: 1.0
     */
    public static ResponseVo verity() {
        HttpServletRequest request = SpringContextUtil.getHttpServletRequest();
        // 从请求头部中获取token信息
        String token = request.getHeader("Authorization");
        if (null == token) {
            log.debug("用户登陆信息过期");
            return ResponseVo.userNeedLogin();
        }
        String account = getUserAccount(token);
        if (!tokenCache.containsKey(account)) {
            log.debug("用户登陆信息过期");
            return ResponseVo.userNeedLogin();
        }
        String tokenAuthorize = tokenCache.get(account);
        if (!tokenAuthorize.equals(token)) {
            log.debug("用户异地登陆");
            return ResponseVo.userNeedLogin();
        }
        try {
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            if (null != jwt) {
                // 拿到我们放置在token中的信息
                List<String> audience = jwt.getAudience();
                if (null != audience) {
                    return ResponseVo.authenticationSuccess(audience.get(0));
                }
            }
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (JWTVerificationException e) {
            e.printStackTrace();
        }
        return ResponseVo.userNeedLogin();
    }
}

